#include "stdafx.h"
#include "Game.h"
#include "OgreUtils.h"
#include <Commdlg.h>
#include <ctime>
using namespace std;


void Game::createScene()
{
	srand(time(0));
	learning = false;
	world.reset(new World(mSceneMgr));
	experiment.reset(new RobotExperiment(world.get()));
	trainer.reset(new Trainer(experiment.get()));
	experiment->reset(true);
	world->setPause(false);
	mCamera->setPosition(-150.f, 70.f, 150.f);
	mCamera->setDirection(1.f, -0.4f, -1.f);
	{
		createPlainNode(mSceneMgr);
		btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0.f, 1.f, 0.f), 0.f);
		btTransform trans;
		trans.setIdentity();
		world->addObject(0, groundShape, trans, 0.f);
	}

	createDirectionalLightNode(mSceneMgr, Ogre::Vector3(0.3f, -1.f, -0.7f));

	setShadows(mSceneMgr);

	setSky(mSceneMgr, mWindow);
	
}

void Game::createFrameListener()
{
	BaseApplication::createFrameListener();
	Ogre::FontManager::getSingleton().getByName("SdkTrays/Caption")->load();
	Ogre::FontManager::getSingleton().getByName("SdkTrays/Value")->load();
	Ogre::StringVector items;
	items.push_back("Iteration");
	items.push_back("Fitness");
	items.push_back("Step");
	panel = mTrayMgr->createParamsPanel(OgreBites::TL_TOPRIGHT, "Panel", 150, items);
	mTrayMgr->createButton(OgreBites::TL_TOPRIGHT, "TrainButton", "Train", 150);
	mTrayMgr->createButton(OgreBites::TL_TOPRIGHT, "ResetButton", "Reset", 150);
	mTrayMgr->createButton(OgreBites::TL_TOPRIGHT, "PauseButton", "Pause", 150);
	mTrayMgr->createButton(OgreBites::TL_TOPRIGHT, "SaveButton", "Save", 150);
	mTrayMgr->createButton(OgreBites::TL_TOPRIGHT, "LoadButton", "Load", 150);
	mTrayMgr->createLabel(OgreBites::TL_NONE, "TrainLabel", "Press 'Space' to finish training...", 500)->hide();
	mTrayMgr->showCursor();
	mCameraMan->setStyle(OgreBites::CS_MANUAL);
}

bool Game::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
	if(!BaseApplication::frameRenderingQueued(evt)) return false;
	if(learning)
	{
		trainer->update();
	}
	else
	{
		experiment->update(true);
	}

	panel->setParamValue("Iteration", Ogre::StringConverter::toString(trainer->getIterationCount()));
	panel->setParamValue("Fitness", Ogre::StringConverter::toString(trainer->getFitness()));
	panel->setParamValue("Step", Ogre::StringConverter::toString(world->getStep()));
	return true;
}


bool Game::mousePressed( const OIS::MouseEvent& arg, OIS::MouseButtonID id)
{
	if(!BaseApplication::mousePressed(arg, id)) return false;

	if(id ==  OIS::MB_Right)
	{
		mTrayMgr->hideCursor();
		mCameraMan->setStyle(OgreBites::CS_FREELOOK);
	}
	return true;
}

bool Game::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
	if(!BaseApplication::mouseReleased(arg, id)) return false;
	if(id ==  OIS::MB_Right)
	{
		mTrayMgr->showCursor();
		mCameraMan->setStyle(OgreBites::CS_MANUAL);
	}
	return true;
}

bool Game::keyPressed( const OIS::KeyEvent &arg )
{
	if(!BaseApplication::keyPressed(arg)) return false;

	if (arg.key == OIS::KC_P)
    {
		world->setPause(!world->getPause());
	}
	else if (arg.key == OIS::KC_E)
    {
		shootBox();
	}
	else if(arg.key == OIS::KC_SPACE && learning)
	{
		endTrain();
	}
	return true;
}

void Game::buttonHit(OgreBites::Button* button)
{
	if(button->getName() == "TrainButton")
	{
		beginTrain();
	}
	else if(button->getName() == "ResetButton")
	{
		experiment->reset(true);
	}
	else if(button->getName() == "PauseButton")
	{
		world->setPause(!world->getPause());
	}
	else if(button->getName() == "SaveButton")
	{
		save();
	}
	else if(button->getName() == "LoadButton")
	{
		load();
		experiment->reset(true);
	}
}

void Game::shootBox()
{
	Ogre::Vector3 camPos = mCamera->getPosition();
	Ogre::Vector3 camDir = mCamera->getDirection();
	btTransform trans;
	trans.setIdentity();
	trans.setOrigin(btVector3(camPos.x, camPos.y, camPos.z));
	btVector3 size(3.f, 3.f, 3.f);
	btCollisionShape* shape = new btBoxShape(size);
	Ogre::SceneNode* node = createMeshNode(world->getSceneManager(), "crate.mesh");
	node->setScale(size.x(), size.y(), size.z());
	float mass = size.x() * size.y() * size.z();
	GameObject* obj = world->addObject(node, shape, trans, mass, true); 
	btVector3 impulse(camDir.x, camDir.y, camDir.z);
	impulse *= 10000.f;
	obj->body->applyCentralImpulse(impulse);
}

void Game::beginTrain()
{
	learning = true;
	mSceneMgr->getRootSceneNode()->setVisible(false);
	Ogre::Plane plane(0.f, 1.f, 0.f, 0.f);
	mSceneMgr->setSkyPlane(0, plane, "");
	mWindow->getViewport(0)->setBackgroundColour(Ogre::ColourValue(0.0f, 0.0f, 0.0f));
	OgreBites::Widget* label = mTrayMgr->getWidget("TrainLabel");
	mTrayMgr->moveWidgetToTray(label, OgreBites::TL_CENTER);
	label->show();
	mTrayMgr->hideCursor();
	world->setPause(false);
}

void Game::endTrain()
{
	learning = false;
	mSceneMgr->getRootSceneNode()->setVisible(true);
	setSky(mSceneMgr, mWindow);
	OgreBites::Widget* label = mTrayMgr->getWidget("TrainLabel");
	mTrayMgr->removeWidgetFromTray(label);
	label->hide();
	mTrayMgr->showCursor();
	experiment->reset(true);
}

void Game::save()
{
	char filename[MAX_PATH];
	OPENFILENAMEA ofn = {};       
	ofn.lStructSize = sizeof(ofn);
	ofn.lpstrFile = filename;
	ofn.lpstrFile[0] = '\0';
	ofn.nMaxFile = sizeof(filename);
	ofn.lpstrFilter ="robo\0*.robo\0All\0*.*\0";
	ofn.nFilterIndex = 1;
	if(GetSaveFileNameA(&ofn))
	{
		ofstream f(filename, ios::binary);
		if(f) trainer->save(f);
	}	
}

void Game::load()
{
	char filename[MAX_PATH];
	OPENFILENAMEA ofn = {};       
	ofn.lStructSize = sizeof(ofn);
	ofn.lpstrFile = filename;
	ofn.lpstrFile[0] = '\0';
	ofn.nMaxFile = sizeof(filename);
	ofn.lpstrFilter ="robo\0*.robo\0All\0*.*\0";
	ofn.nFilterIndex = 1;
	if(GetOpenFileNameA(&ofn))
	{
		ifstream f(filename, ios::binary);
		if(f)  trainer->load(f);
	}
}